//
// Created by hunan on 25-7-13.
//

#include "download_file_operate.h"
#include "download_fragment.h"
#include "download_rate.h"
#include "public_module/file_module/file_handle.h"
#include "public_module/openssl_util/openssl_util.h"

#include <cstring>

DownloadFileOperate::DownloadFileOperate(FileData & data)
{
    m_file_data = data;
    m_fragment  = std::make_shared<DownloadFragment>(m_file_data.m_file_size, 1024 * 10);
    m_file_handle = std::make_shared<FileHandle>(m_file_data.m_file_name);
    m_file_handle->OpenFileAppendWrite();
    m_rate = std::make_shared<DownloadRate>();
}

int DownloadFileOperate::InitDownloadFileOperate()
{
    m_fragment->FragmentDataSize();
    uint64_t file_size = m_file_handle->GetFileSize();
    if (file_size > 0)
    {
        m_start_index = m_fragment->RemoveLocalFragment(file_size);
        return EmFileOperateHasFileContent;
    }
    else
    {
        m_start_index = 0;
    }
    return EmFileOperateNothing;
}

bool DownloadFileOperate::IsLargeFile() const
{
    return m_fragment->IsFragmentDataSize();
}

bool DownloadFileOperate::GetOneFragment(int & min, int & max) const
{
    return m_fragment->GetOneFragment(min, max);
}

void DownloadFileOperate::DownFileDataFail(int min, int max) const
{
    m_fragment->Update(min, max, DownloadFragment::EmFailed);
}

void DownloadFileOperate::PushFileData(int min, int max, const uint8_t * data, int data_size)
{
    m_fragment->Update(min, max, DownloadFragment::EmDone);
    m_rate->AddData(data_size);
    if (m_start_index == min)
    {
        m_file_handle->Write(data, data_size);
        m_start_index = max + 1;
        while (true)
        {
            auto iter = m_data_vec_map.find(m_start_index);
            if (iter == m_data_vec_map.end())
            {
                break;
            }
            m_file_handle->Write(iter->second.data(), iter->second.size());
            m_start_index = m_start_index + iter->second.size();
            m_data_vec_map.erase(iter);
        }
    }
    else
    {
        auto & vec = m_data_vec_map[min];
        vec.resize(data_size);
        memcpy(vec.data(), data, data_size);
    }
}

uint64_t DownloadFileOperate::GetLocalFileSize() const
{
    return m_file_handle->GetFileSize();
}

std::string DownloadFileOperate::GetLocalFileHash() const
{
    std::string result;
    OpenSSLUtil::ComputeFileMD5(m_file_data.m_file_name, result);
    return result;
}

uint64_t DownloadFileOperate::GetRemoteFileSize() const
{
    return m_file_data.m_file_size;
}

bool DownloadFileOperate::DownloadAll() const
{
    bool result = m_fragment->IsGetFragmentAll();
    return result;
}

void DownloadFileOperate::WriteToFile()
{
    for (auto & data : m_data_vec_map)
    {
        m_file_handle->Write(data.second.data(), data.second.size());
    }
    m_data_vec_map.clear();
}

void DownloadFileOperate::PrintStatistic() const
{
    m_rate->PrintStatistic();
}








